package com.stefanie.eventlistenerdemo.common.event;

import com.stefanie.eventlistenerdemo.listener.core.EventListener;
import org.springframework.scheduling.annotation.Async;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author: stefanie-zy
 * @time: 2024/1/12-14:34
 * @description: 公共-广播器实现
 */
public class EventMulticasterImpl implements EventMulticaster {

    // 事件监听器Map
    private final Map<Class<?>, List<EventListener>> eventListenerMap = new ConcurrentHashMap<>();


    @Override
    @Async("stefanieExecutor")
    public void multicastEvent(CommonEvent event) {
        List<EventListener> eventListeners = this.eventListenerMap.get(event.getClass());
        if (eventListeners != null) {
            eventListeners.forEach(eventListener -> eventListener.onEvent(event));
        }
    }

    /**
     * @description: 举例说明：系统中有UserEvent、TaskEvent...，其中新增了张三、李四、王五，触发了UserListener，会产生3个UserEvent事件，分别由3个监听器去处理业务[zsUserListener、lsUserListener、wwUserListener]，新增监听器的时候需要反向找到对应的时间类型，即UserEvent。
     */

    @Override
    public void addEventListener(EventListener<?> eventListener) {
        Class<?> eventType = this.getEventType(eventListener);
        List<EventListener> eventListeners = this.eventListenerMap.get(eventType);
        if (eventListeners == null) {
            eventListeners = new ArrayList<>();
            eventListenerMap.put(eventType, eventListeners);
        }
        eventListeners.add(eventListener);
    }

    @Override
    public void removeEventListener(EventListener<?> eventListener) {
        Class<?> eventType = this.getEventType(eventListener);
        List<EventListener> eventListeners = this.eventListenerMap.get(eventType);
        if (eventListeners != null) {
            eventListeners.remove(eventListener);
        }
    }

    /**
     * 获取事件监听器的事件类型
     *
     * @param eventListener 事件监听器
     * @return 事件类型
     */
    protected Class<?> getEventType(EventListener eventListener) {
        ParameterizedType parameterizedType = (ParameterizedType) eventListener.getClass().getGenericInterfaces()[0];
        Type eventType = parameterizedType.getActualTypeArguments()[0];
        return (Class<?>) eventType;
    }
}
